<template>
	<div class="rich-text-editor">
		<!-- 工具栏 -->
		<div v-if="showToolbar" class="toolbar" :class="{ compact: props.compact }">
			<!-- 基础格式 -->
			<div
				v-if="
					props.toolbar.bold ||
					props.toolbar.italic ||
					props.toolbar.underline ||
					props.toolbar.strikethrough
				"
				class="toolbar-group">
				<a-button-group>
					<a-button
						v-if="props.toolbar.bold"
						:type="isBold ? 'primary' : 'default'"
						@click="toggleBold"
						class="toolbar-btn">
						<template #icon>
							<BoldOutlined />
						</template>
					</a-button>
					<a-button
						v-if="props.toolbar.italic"
						:type="isItalic ? 'primary' : 'default'"
						@click="toggleItalic"
						class="toolbar-btn">
						<template #icon>
							<ItalicOutlined />
						</template>
					</a-button>
					<a-button
						v-if="props.toolbar.underline"
						:type="isUnderline ? 'primary' : 'default'"
						@click="toggleUnderline"
						class="toolbar-btn">
						<template #icon>
							<UnderlineOutlined />
						</template>
					</a-button>
					<a-button
						v-if="props.toolbar.strikethrough"
						:type="isStrikethrough ? 'primary' : 'default'"
						@click="toggleStrikethrough"
						class="toolbar-btn">
						<template #icon>
							<StrikethroughOutlined />
						</template>
					</a-button>
				</a-button-group>
			</div>

			<!-- 字体设置 -->
			<div
				v-if="
					props.toolbar.fontSize || props.toolbar.fontFamily || props.toolbar.lineHeight
				"
				class="toolbar-group">
				<a-select
					v-if="props.toolbar.fontSize"
					v-model:value="fontSize"
					:options="fontSizeOptions"
					style="width: 80px"
					placeholder="字号" />
				<a-select
					v-if="props.toolbar.fontFamily"
					v-model:value="fontFamily"
					:options="fontFamilyOptions"
					style="width: 120px"
					placeholder="字体" />
				<a-select
					v-if="props.toolbar.lineHeight"
					v-model:value="lineHeight"
					:options="lineHeightOptions"
					style="width: 80px"
					placeholder="行高" />
			</div>

			<!-- 插入功能 -->
			<div
				v-if="props.toolbar.link || props.toolbar.image || props.toolbar.table"
				class="toolbar-group">
				<a-button-group>
					<a-button v-if="props.toolbar.link" @click="insertLink" class="toolbar-btn">
						<template #icon>
							<LinkOutlined />
						</template>
					</a-button>
					<a-button v-if="props.toolbar.image" @click="insertImage" class="toolbar-btn">
						<template #icon>
							<PictureOutlined />
						</template>
					</a-button>
					<a-button v-if="props.toolbar.table" @click="insertTable" class="toolbar-btn">
						<template #icon>
							<TableOutlined />
						</template>
					</a-button>
				</a-button-group>
			</div>

			<!-- 对齐方式 -->
			<div
				v-if="
					props.toolbar.alignLeft || props.toolbar.alignCenter || props.toolbar.alignRight
				"
				class="toolbar-group">
				<a-button-group>
					<a-button v-if="props.toolbar.alignLeft" @click="alignLeft" class="toolbar-btn">
						<template #icon>
							<AlignLeftOutlined />
						</template>
					</a-button>
					<a-button
						v-if="props.toolbar.alignCenter"
						@click="alignCenter"
						class="toolbar-btn">
						<template #icon>
							<AlignCenterOutlined />
						</template>
					</a-button>
					<a-button
						v-if="props.toolbar.alignRight"
						@click="alignRight"
						class="toolbar-btn">
						<template #icon>
							<AlignRightOutlined />
						</template>
					</a-button>
				</a-button-group>
			</div>

			<!-- 历史记录 -->
			<div v-if="props.toolbar.undo || props.toolbar.redo" class="toolbar-group">
				<a-button-group>
					<a-button
						v-if="props.toolbar.undo"
						@click="undo"
						:disabled="!canUndo"
						class="toolbar-btn">
						<template #icon>
							<UndoOutlined />
						</template>
					</a-button>
					<a-button
						v-if="props.toolbar.redo"
						@click="redo"
						:disabled="!canRedo"
						class="toolbar-btn">
						<template #icon>
							<RedoOutlined />
						</template>
					</a-button>
				</a-button-group>
			</div>

			<!-- 自定义工具栏组 -->
			<template v-for="group in props.toolbar.customGroups" :key="group.name">
				<div class="toolbar-group">
					<template v-for="item in group.items" :key="item.label">
						<!-- 按钮类型 -->
						<a-button
							v-if="item.type === 'button'"
							@click="item.action"
							class="toolbar-btn">
							<template #icon v-if="item.icon">
								<component :is="getIconComponent(item.icon)" />
							</template>
							{{ item.label }}
						</a-button>

						<!-- 选择器类型 -->
						<a-select
							v-else-if="item.type === 'select'"
							v-model:value="item.value"
							:options="item.options"
							:style="{ width: '120px' }"
							:placeholder="item.label"
							@change="item.onChange" />
					</template>
				</div>
			</template>
		</div>

		<!-- 编辑区域 -->
		<div
			ref="editorRef"
			class="editor-area"
			contenteditable="true"
			@input="handleInput"
			@focus="handleFocus"
			@blur="handleBlur"
			@keydown="handleKeydown"
			:style="{
				fontSize: `${fontSize}px`,
				fontFamily: fontFamily,
				lineHeight: lineHeight
			}"></div>

		<!-- 链接插入模态框 -->
		<a-modal
			v-model:open="linkModalVisible"
			title="插入链接"
			@ok="confirmLink"
			@cancel="cancelLink">
			<a-form layout="vertical">
				<a-form-item label="链接地址">
					<a-input v-model:value="linkUrl" placeholder="请输入链接地址" />
				</a-form-item>
				<a-form-item label="链接文本">
					<a-input v-model:value="linkText" placeholder="请输入链接文本" />
				</a-form-item>
			</a-form>
		</a-modal>

		<!-- 图片插入模态框 -->
		<a-modal
			v-model:open="imageModalVisible"
			title="插入图片"
			@ok="confirmImage"
			@cancel="cancelImage">
			<a-form layout="vertical">
				<a-form-item label="图片地址">
					<a-input v-model:value="imageUrl" placeholder="请输入图片地址" />
				</a-form-item>
				<a-form-item label="图片描述">
					<a-input v-model:value="imageAlt" placeholder="请输入图片描述" />
				</a-form-item>
			</a-form>
		</a-modal>
	</div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, watch, nextTick } from 'vue'
import {
	BoldOutlined,
	ItalicOutlined,
	UnderlineOutlined,
	StrikethroughOutlined,
	LinkOutlined,
	PictureOutlined,
	TableOutlined,
	AlignLeftOutlined,
	AlignCenterOutlined,
	AlignRightOutlined,
	UndoOutlined,
	RedoOutlined
} from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'

// 工具栏配置类型
interface ToolbarConfig {
	// 基础格式
	bold?: boolean
	italic?: boolean
	underline?: boolean
	strikethrough?: boolean
	// 字体设置
	fontSize?: boolean
	fontFamily?: boolean
	lineHeight?: boolean
	// 对齐方式
	alignLeft?: boolean
	alignCenter?: boolean
	alignRight?: boolean
	// 插入功能
	link?: boolean
	image?: boolean
	table?: boolean
	// 历史记录
	undo?: boolean
	redo?: boolean
	// 自定义工具栏组
	customGroups?: ToolbarGroup[]
}

interface ToolbarGroup {
	name: string
	items: ToolbarItem[]
}

interface ToolbarItem {
	type: 'button' | 'select' | 'custom'
	label?: string
	icon?: string
	action?: () => void
	options?: Array<{ value: any; label: string }>
	value?: any
	onChange?: (value: any) => void
}

// 组件属性
interface Props {
	modelValue?: string
	placeholder?: string
	height?: string
	toolbar?: ToolbarConfig
	compact?: boolean
}

const props = withDefaults(defineProps<Props>(), {
	modelValue: '',
	placeholder: '请输入内容...',
	height: '90px', // 默认3行文字的高度 约90px
	toolbar: () => ({
		bold: true,
		italic: true,
		underline: true,
		strikethrough: true,
		fontSize: true,
		fontFamily: true,
		lineHeight: true,
		alignLeft: true,
		alignCenter: true,
		alignRight: true,
		link: false,
		image: false,
		table: false,
		undo: true,
		redo: true, // 默认显示重做按钮
		customGroups: []
	}),
	compact: false
})

const emit = defineEmits<{
	'update:modelValue': [value: string]
	change: [value: string]
}>()

// 响应式数据
const editorRef = ref<HTMLElement>()
const isBold = ref(false)
const isItalic = ref(false)
const isUnderline = ref(false)
const isStrikethrough = ref(false)
const fontSize = ref(14)
const fontFamily = ref('Arial, sans-serif')
const lineHeight = ref(1.0) // 默认行高为1
const linkModalVisible = ref(false)
const imageModalVisible = ref(false)
const linkUrl = ref('')
const linkText = ref('')
const imageUrl = ref('')
const imageAlt = ref('')

// 历史记录
const history = ref<string[]>([])
const historyIndex = ref(-1)

// 选项配置
const fontSizeOptions = [
	{ value: 12, label: '12px' },
	{ value: 14, label: '14px' },
	{ value: 16, label: '16px' },
	{ value: 18, label: '18px' },
	{ value: 20, label: '20px' },
	{ value: 24, label: '24px' },
	{ value: 28, label: '28px' },
	{ value: 32, label: '32px' }
]

const fontFamilyOptions = [
	// 中文字体
	{ value: 'Microsoft YaHei, sans-serif', label: '微软雅黑' },
	{ value: 'SimSun, serif', label: '宋体' },
	{ value: 'SimHei, sans-serif', label: '黑体' },
	{ value: 'KaiTi, serif', label: '楷体' },
	{ value: 'FangSong, serif', label: '仿宋' },
	{ value: 'PingFang SC, sans-serif', label: '苹方' },
	{ value: 'Hiragino Sans GB, sans-serif', label: '冬青黑体' },
	{ value: 'Source Han Sans CN, sans-serif', label: '思源黑体' },
	{ value: 'Source Han Serif CN, serif', label: '思源宋体' },
	// 英文字体
	{ value: 'Arial, sans-serif', label: 'Arial' },
	{ value: 'Helvetica, sans-serif', label: 'Helvetica' },
	{ value: 'Georgia, serif', label: 'Georgia' },
	{ value: 'Times New Roman, serif', label: 'Times New Roman' },
	{ value: 'Courier New, monospace', label: 'Courier New' },
	{ value: 'Verdana, sans-serif', label: 'Verdana' },
	{ value: 'Tahoma, sans-serif', label: 'Tahoma' },
	{ value: 'Trebuchet MS, sans-serif', label: 'Trebuchet MS' },
	{ value: 'Impact, sans-serif', label: 'Impact' },
	{ value: 'Comic Sans MS, sans-serif', label: 'Comic Sans MS' },
	// 等宽字体
	{ value: 'Consolas, monospace', label: 'Consolas' },
	{ value: 'Monaco, monospace', label: 'Monaco' },
	{ value: 'Menlo, monospace', label: 'Menlo' },
	{ value: 'Courier, monospace', label: 'Courier' },
	// 手写字体
	{ value: 'Brush Script MT, cursive', label: 'Brush Script' },
	{ value: 'Lucida Handwriting, cursive', label: 'Lucida Handwriting' }
]

const lineHeightOptions = [
	{ value: 1.0, label: '1.0' },
	{ value: 1.2, label: '1.2' },
	{ value: 1.4, label: '1.4' },
	{ value: 1.6, label: '1.6' },
	{ value: 1.8, label: '1.8' },
	{ value: 2.0, label: '2.0' },
	{ value: 2.5, label: '2.5' },
	{ value: 3.0, label: '3.0' }
]

// 计算属性
const canUndo = computed(() => historyIndex.value > 0)
const canRedo = computed(() => historyIndex.value < history.value.length - 1)

// 是否显示工具栏
const showToolbar = computed(() => {
	const { toolbar } = props
	return (
		toolbar.bold ||
		toolbar.italic ||
		toolbar.underline ||
		toolbar.fontSize ||
		toolbar.fontFamily ||
		toolbar.alignLeft ||
		toolbar.alignCenter ||
		toolbar.alignRight ||
		toolbar.link ||
		toolbar.image ||
		toolbar.table ||
		toolbar.undo ||
		toolbar.redo ||
		// eslint-disable-next-line no-extra-parens
		(toolbar.customGroups && toolbar.customGroups.length > 0)
	)
})

// 方法
const saveToHistory = () => {
	if (!editorRef.value) return

	const content = editorRef.value.innerHTML
	// 移除当前索引之后的历史记录
	history.value = history.value.slice(0, historyIndex.value + 1)
	history.value.push(content)
	historyIndex.value = history.value.length - 1

	// 限制历史记录数量
	if (history.value.length > 50) {
		history.value.shift()
		historyIndex.value = history.value.length - 1
	}
}

const updateEditorState = () => {
	if (!editorRef.value) return

	// 使用 nextTick 确保在 DOM 更新后显示选择变化
	nextTick(() => {
		setTimeout(() => {
			isBold.value = document.queryCommandState('bold')
			isItalic.value = document.queryCommandState('italic')
			isUnderline.value = document.queryCommandState('underline')
			isStrikethrough.value = document.queryCommandState('strikeThrough')
		}, 100)
	})
}

const execCommand = (command: string, value?: string) => {
	// 执行命令
	document.execCommand(command, false, value)

	// 确保编辑器保持焦点
	editorRef.value?.focus()

	updateEditorState()
}

const handleInput = () => {
	if (!editorRef.value) return

	let content = editorRef.value.innerHTML

	// 确保内容有基本的HTML标签包裹
	if (content.trim() && !content.includes('<') && !content.includes('>')) {
		content = `<p style="text-align: left;">${content}</p>`
		editorRef.value.innerHTML = content
	}

	emit('update:modelValue', content)
	emit('change', content)
	saveToHistory()
}

const handleFocus = () => {
	editorRef.value?.classList.add('focused')
}

const handleBlur = () => {
	editorRef.value?.classList.remove('focused')
}

// 工具栏方法
const undo = () => {
	if (canUndo.value) {
		historyIndex.value--
		if (editorRef.value) {
			editorRef.value.innerHTML = history.value[historyIndex.value]
			emit('update:modelValue', editorRef.value.innerHTML)
			emit('change', editorRef.value.innerHTML)
		}
	}
}

const redo = () => {
	if (canRedo.value) {
		historyIndex.value++
		if (editorRef.value) {
			editorRef.value.innerHTML = history.value[historyIndex.value]
			emit('update:modelValue', editorRef.value.innerHTML)
			emit('change', editorRef.value.innerHTML)
		}
	}
}

const handleKeydown = (event: KeyboardEvent) => {
	// 处理 Ctrl+Z 和 Ctrl+Y
	if (event.ctrlKey || event.metaKey) {
		if (event.key === 'z') {
			event.preventDefault()
			undo()
		} else if (event.key === 'y') {
			event.preventDefault()
			redo()
		}
	}
}

const toggleBold = () => execCommand('bold')
const toggleItalic = () => execCommand('italic')
const toggleUnderline = () => execCommand('underline')
const toggleStrikethrough = () => execCommand('strikeThrough')

const alignLeft = () => execCommand('justifyLeft')
const alignCenter = () => execCommand('justifyCenter')
const alignRight = () => execCommand('justifyRight')

const insertLink = () => {
	linkUrl.value = ''
	linkText.value = ''
	linkModalVisible.value = true
}

const insertImage = () => {
	imageUrl.value = ''
	imageAlt.value = ''
	imageModalVisible.value = true
}

const insertTable = () => {
	const tableHtml = `
    <table border="1" style="width: 100%; border-collapse: collapse;">
      <tr>
        <td style="padding: 8px;">单元格1</td>
        <td style="padding: 8px;">单元格2</td>
      </tr>
      <tr>
        <td style="padding: 8px;">单元格3</td>
        <td style="padding: 8px;">单元格4</td>
      </tr>
    </table>
  `
	execCommand('insertHTML', tableHtml)
}

const confirmLink = () => {
	if (!linkUrl.value.trim()) {
		message.warning('请输入链接地址')
		return
	}

	const linkHtml = `<a href="${linkUrl.value}" target="_blank">${linkText.value || linkUrl.value}</a>`
	execCommand('insertHTML', linkHtml)
	linkModalVisible.value = false
}

const cancelLink = () => {
	linkModalVisible.value = false
}

const confirmImage = () => {
	if (!imageUrl.value.trim()) {
		message.warning('请输入图片地址')
		return
	}

	const imgHtml = `<img src="${imageUrl.value}" alt="${imageAlt.value}" style="max-width: 100%;">`
	execCommand('insertHTML', imgHtml)
	imageModalVisible.value = false
}

const cancelImage = () => {
	imageModalVisible.value = false
}

// 清空内容
const clear = () => {
	if (editorRef.value) {
		editorRef.value.innerHTML = ''
		emit('update:modelValue', '')
		emit('change', '')
		saveToHistory()
	}
}

// 获取纯文本内容
const getPlainText = (): string => {
	return editorRef.value?.innerText || ''
}

// 获取HTML内容
const getHTML = (): string => {
	return editorRef.value?.innerHTML || ''
}

// 设置内容
const setContent = (content: string) => {
	if (editorRef.value) {
		editorRef.value.innerHTML = content
		emit('update:modelValue', content)
		emit('change', content)
		saveToHistory()
	}
}

// 生命周期
onMounted(() => {
	if (editorRef.value) {
		editorRef.value.innerHTML = props.modelValue
		saveToHistory()

		// 设置占位符
		if (!props.modelValue && props.placeholder) {
			editorRef.value.setAttribute('data-placeholder', props.placeholder)
		}

		// 确保内容默认左对齐
		if (editorRef.value.innerHTML.trim() === '') {
			editorRef.value.style.textAlign = 'left'
		}
	}
})

// 监听外部值变化
watch(
	() => props.modelValue,
	newValue => {
		if (editorRef.value && editorRef.value.innerHTML !== newValue) {
			editorRef.value.innerHTML = newValue
			saveToHistory()
		}
	}
)

// 获取图标组件
const getIconComponent = (iconName: string) => {
	const iconMap: Record<string, any> = {
		BoldOutlined: BoldOutlined,
		ItalicOutlined: ItalicOutlined,
		UnderlineOutlined: UnderlineOutlined,
		LinkOutlined: LinkOutlined,
		PictureOutlined: PictureOutlined,
		TableOutlined: TableOutlined,
		AlignLeftOutlined: AlignLeftOutlined,
		AlignCenterOutlined: AlignCenterOutlined,
		AlignRightOutlined: AlignRightOutlined,
		UndoOutlined: UndoOutlined,
		RedoOutlined: RedoOutlined
	}
	return iconMap[iconName] || null
}

// 暴露方法给父组件
defineExpose({
	clear,
	getPlainText,
	getHTML,
	setContent,
	undo,
	redo
})
</script>

<style scoped>
.rich-text-editor {
	border: 1px solid #d9d9d9;
	border-radius: 6px;
	overflow: hidden;
	background: white;
}

.toolbar {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 8px 12px;
	border-bottom: 1px solid #f0f0f0;
	background: #fafafa;
	flex-wrap: wrap;
}

.toolbar-group {
	display: flex;
	align-items: center;
	gap: 4px;
}

.toolbar-btn {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 4px 8px;
	min-width: auto;
}

/* 紧凑模式样式 */
.toolbar.compact {
	padding: 4px 8px;
	gap: 4px;
}

.toolbar.compact .toolbar-group {
	gap: 2px;
}

.toolbar.compact .toolbar-btn {
	padding: 2px 6px;
	font-size: 12px;
}

.toolbar.compact .ant-select {
	font-size: 12px;
}

.toolbar.compact .ant-select .ant-select-selector {
	padding: 2px 8px;
	min-height: 24px;
}

.editor-area {
	min-height: v-bind(height);
	padding: 12px;
	outline: none;
	overflow-y: auto;
	line-height: 1.6;
}

.editor-area:focus {
	border-color: #4096ff;
	box-shadow: 0 0 0 2px rgba(5, 145, 255, 0.1);
}

.editor-area[data-placeholder]:empty:before {
	content: attr(data-placeholder);
	color: #bfbfbf;
}

.editor-area:empty:before {
	content: attr(data-placeholder);
	color: #bfbfbf;
}

.editor-area.focused {
	border-color: #4096ff;
}

/* 自定义滚动条 */
.editor-area::-webkit-scrollbar {
	width: 6px;
}

.editor-area::-webkit-scrollbar-track {
	background: #f1f1f1;
	border-radius: 3px;
}

.editor-area::-webkit-scrollbar-thumb {
	background: #c1c1c1;
	border-radius: 3px;
}

.editor-area::-webkit-scrollbar-thumb:hover {
	background: #a8a8a8;
}
</style>
